﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Publishing;

namespace RecycleOrDeleteFiles
{


    /// <summary> 
    /// This applicaiton recycles / deletes all draft and un-used versions of files 
    /// http://johnnyharbieh.spaces.live.com/blog/cns!C1E28E97CCB39CC2!308.entry
    /// </summary> 
    class Program
    {
        // Used to track the total # of files affected by the Recycle or Delete operation 
        private static int filesRecycled = 0;
        private static int filesDeleted = 0;
        private static int versionsRecycled = 0;
        private static int versionsDeleted = 0;
        private static int restoredVersions = 0;

        static void Main(string[] args)
        {
            // Used to hold arguments and parameters passed to this application 
            string operation = null;
            string operationName = null;
            string url = null;
            string urlPath = null;
            string folder = null;
            string folderNames = null;
            string includeSubFolders = null;

            try
            {
                // Make sure I have exactly what I am looking for, 4 required arguments 
                if (args.Length == 0 || args.Length < 4)
                {
                    displayUsage(null);

                    // Return to caller 
                    return;
                }
                else
                {
                    // Verify my passed arguments and reformat as neccessary (All lower case) 
                    operation = (args.Length > 0 && args[0] != null && args[0].ToLower() == "-o") ? args[0].ToLower() : null;
                    operationName = (args.Length > 1 && args[1] != null && (args[1].ToLower() == "recycleall" || args[1].ToLower() == "deleteall" || args[1].ToLower() == "restoreallsilent" || args[1].ToLower() == "restoreallverbose")) ? args[1].ToLower() : null;
                    url = (args.Length > 2 && args[2] != null && args[2].ToLower() == "-url") ? args[2].ToLower() : null;
                    urlPath = (args.Length > 3 && args[3] != null) ? args[3].ToLower() : null;

                    // Optional arguments 
                    folder = (args.Length > 4 && args[4] != null && args[4].ToLower() == "-folders") ? args[4].ToLower() : null;
                    folderNames = (args.Length > 5 && args[5] != null && args[5].Split(',') != null) ? args[5].ToLower() : null;
                    includeSubFolders = (args.Length > 6 && args[6] != null && (args[6].ToLower()) == "-includesubfolders") ? args[6].ToLower() : null;

                    // Make sure we have a valid site collection to work with 
                    bool validSiteCollection = isValidSiteCollection(urlPath);

                    // See if we need to include child folders 
                    bool includeChildFolders = (includeSubFolders != null) ? true : false;

                    // Use this array to load folders 
                    string[] foldersArray = null;

                    // Check to see if we have a set of folders to work with, if not, just use the Pages folder as default 
                    if (folder != null && folderNames != null)
                    {
                        if (folderNames.Contains(","))
                        {
                            foldersArray = folderNames.Split(',');
                        }
                        else
                        {
                            foldersArray = new string[1];
                            foldersArray[0] = folderNames;
                        }
                    }
                    else
                    {
                        // Set default folder name value 
                        foldersArray =

                        new string[1];
                        foldersArray[0] = "pages";
                    }


                    // Do we have all what we need to start the work. Required only arguments 

                    if (operation != null && operationName != null && url != null && urlPath != null && validSiteCollection)
                    {
                        // Split the operations here 

                        switch (operationName)
                        {
                            case "recycleall":
                                System.Console.WriteLine("Starting process ...");

                                // Run this piece of code with elevated permissions to enable us to access the AllWebs and execute our cleanup process. 

                                // This piece of code is exaclty the same for Delete All except for the file methods that are called on individual files. 
                                SPSecurity.RunWithElevatedPrivileges(

                                delegate()
                                {

                                    SPSite siteCollection = new SPSite(urlPath);

                                    if (siteCollection != null)
                                    {
                                        SPWebCollection webCollection = siteCollection.AllWebs;

                                        foreach (SPWeb web in webCollection)
                                        {
                                            // Web Template IDs: 90 = Search, 53 = Publishing, 1 = Collaboration 
                                            System.Console.WriteLine("Looking into web: {0} with template id of: {1}", web.Url, web.WebTemplateId.ToString());

                                            // Access only publishing templates 
                                            if (PublishingWeb.IsPublishingWeb(web))
                                            {
                                                foreach (object folderItem in foldersArray)
                                                {
                                                    string folderName = folderItem.ToString().Trim();

                                                    try
                                                    {
                                                        System.Console.WriteLine("Looking into folder: {0}", folderName);

                                                        if (web.Folders != null && web.Folders[folderName] != null)
                                                        {
                                                            // Recycle this folder and of its sub folders files 
                                                            recycleFileVersionsInFoldersAndSubFolders(web.GetFolder(folderName), includeChildFolders);
                                                        }
                                                    }


                                                    catch (Exception ex)
                                                    {
                                                        if (ex.Message == "Value does not fall within the expected range.")
                                                        {
                                                            System.Console.WriteLine("Folder does not exist: {0}", folderName);
                                                        }
                                                    }
                                                }

                                            }



                                            // Clean up the web and its container's recycle bins 
                                            if (filesRecycled > 0)
                                            {

                                                System.Console.WriteLine("Moving items in recycle bin to second stage for web: {0}", web.Url);
                                                web.RecycleBin.MoveAllToSecondStage();
                                                web.Site.RecycleBin.MoveAllToSecondStage();

                                            }

                                        }

                                    }

                                }

                                );

                                System.Console.WriteLine("Finished process ...");
                                System.Console.WriteLine("Total files: {0}, versions: {1}", filesRecycled.ToString(), versionsRecycled.ToString());

                                break;

                            case "deleteall":
                                System.Console.WriteLine("Starting process...");
                                SPSecurity.RunWithElevatedPrivileges(
                                delegate()
                                {
                                    SPSite siteCollection = new SPSite(urlPath);
                                    if (siteCollection != null)
                                    {
                                        SPWebCollection webCollection = siteCollection.AllWebs;
                                        foreach (SPWeb web in webCollection)
                                        {
                                            System.Console.WriteLine("Looking into web: {0} with template id of: {1}", web.Url, web.WebTemplateId.ToString());
                                            
                                            // Access only publishing templates 
                                            if (PublishingWeb.IsPublishingWeb(web))
                                            {

                                                foreach (object folderItem in foldersArray)
                                                {
                                                    string folderName = folderItem.ToString().Trim();
                                                    try
                                                    {
                                                        System.Console.WriteLine("Looking into folder: {0}", folderName);
                                                        if (web.Folders != null && web.Folders[folderName] != null)
                                                        {
                                                            // Delete this folder's files and of its sub folders' files 
                                                            deleteFileVersionsInFoldersAndSubFolders(web.GetFolder(folderName), includeChildFolders);
                                                        }

                                                    }
                                                    catch (Exception ex)
                                                    {
                                                        if (ex.Message == "Value does not fall within the expected range.")
                                                        {
                                                            System.Console.WriteLine("Folder does not exist: {0}", folderName);
                                                        }
                                                    }
                                                }
                                            }

                                            // Delete all versions from web and its container's recycle bins 

                                            if (filesDeleted > 0)
                                            {

                                                System.Console.WriteLine("Deleting items in recycle bin for web: {0}", web.Url);
                                                web.RecycleBin.DeleteAll();

                                                web.Site.RecycleBin.DeleteAll();

                                            }

                                        }

                                    }

                                }

                                );

                                System.Console.WriteLine("Finished process ...");
                                System.Console.WriteLine("Total files: {0}, versions: {1}", filesDeleted.ToString(), versionsDeleted.ToString());

                                break;

                            case "restoreallverbose":
                                System.Console.WriteLine("Starting process...");
                                SPSecurity.RunWithElevatedPrivileges(
                                delegate()
                                {

                                    SPSite siteCollection = new SPSite(urlPath);
                                    SPRecycleBinItemCollection recycleBinItemCollection = siteCollection.RecycleBin;

                                    SPRecycleBinItemCollection recycleBinItemWorkableCollection = siteCollection.RecycleBin;

                                    if (recycleBinItemCollection != null && recycleBinItemCollection.Count > 0)
                                    {

                                        foreach (SPRecycleBinItem recycleBinItem in recycleBinItemCollection)
                                        {

                                            System.Console.WriteLine("Restoring item: {0}/{1}", recycleBinItem.DirName, recycleBinItem.LeafName);

                                            Guid[] itemIDArray = null;
                                            itemIDArray = new Guid[1];
                                            itemIDArray[0] = recycleBinItem.ID;

                                            recycleBinItemWorkableCollection.Restore(itemIDArray);

                                            restoredVersions += 1;

                                        }

                                    }

                                }

                                );

                                System.Console.WriteLine("Finished process ...");
                                System.Console.WriteLine("Total restored versions: {0}", restoredVersions.ToString());

                                break;

                            case "restoreallsilent":
                                System.Console.WriteLine("Starting process...");
                                SPSecurity.RunWithElevatedPrivileges(
                                delegate()
                                {

                                    SPSite siteCollection = new SPSite(urlPath);
                                    SPRecycleBinItemCollection recycleBinItemCollection = siteCollection.RecycleBin;

                                    restoredVersions = recycleBinItemCollection.Count;

                                    recycleBinItemCollection.RestoreAll();
                                }

                                );

                                System.Console.WriteLine("Finished process ...");
                                System.Console.WriteLine("Total restored versions: {0}", restoredVersions.ToString());

                                break;

                            default:

                                break;
                        }

                    }


                    else
                    {

                        displayUsage("Sorry, parameter set is not valid. See below for more information:");
                    }

                }

            }


            catch (Exception ex)
            {

                System.Console.WriteLine("Error occured");
                System.Console.WriteLine("Message: {0}", ex.Message);
                System.Console.WriteLine("Source: {0}", ex.Source);
                System.Console.WriteLine("Stack Trace: {0}", ex.StackTrace);

                return;
            }


            finally
            {

            }

        }



        /// <summary> 
        /// Display a usage message plus any other custom message. Custom messages display on top 
        /// </summary> 
        /// <param name="message">A custom message to be passed to the usage display routine</param> 
        private static void displayUsage(string message)
        {


            if (message != null)
            {

                System.Console.WriteLine(message);
            }

            System.Console.WriteLine("");
            System.Console.WriteLine("CORP SharePoint Administration tool usage: ");
            System.Console.WriteLine("");
            System.Console.WriteLine("Operations: ");
            System.Console.WriteLine(" recycleall");
            System.Console.WriteLine(" deleteall");
            System.Console.WriteLine(" restoreallsilent");
            System.Console.WriteLine(" restoreallverbose");
            System.Console.WriteLine("");
            System.Console.WriteLine("Switches: ");
            System.Console.WriteLine(" -o");
            System.Console.WriteLine(" -url");
            System.Console.WriteLine(" -folders");
            System.Console.WriteLine(" -includesubfolders");
            System.Console.WriteLine("Example: ");
            System.Console.WriteLine("RecycleOrDeleteFiles -o <operation> -url <site collection url> [-folders <folder1, folder2, folder3> | -includesubfolders]");
            System.Console.WriteLine("RecycleOrDeleteFiles -o recycleall -url http://sitecollection -folders pages,sitecollectionimages,_catalogs -includesubfolders");
            System.Console.WriteLine("");
        }


        /// <summary> 

        /// Deletes files located in this folder plus any other sub folders underneath it using an iterative method 

        /// </summary> 

        /// <param name="instance">A SharePoint folder instance</param> 

        /// <param name="includeChildFolders">A boolean specifying whether to include child folders or not</param> 

        private static void deleteFileVersionsInFoldersAndSubFolders(SPFolder instance, bool includeChildren)
        {


            try
            {

                SPFileCollection files = instance.Files;


                if (files != null && files.Count > 0)
                {
                    foreach (SPFile file in files)
                    {
                        if (file.Versions.Count > 0)
                        {

                            versionsDeleted += file.Versions.Count;
                            filesDeleted += 1;
                            System.Console.WriteLine("Deleting versions of file: {0}", file.Url);
                            file.Versions.DeleteAll();
                        }

                    }

                }


                if (includeChildren)
                {


                    if (instance.SubFolders != null)
                    {


                        foreach (SPFolder subFolder in instance.SubFolders)
                        {
                            // Recycle second level sub folder files 
                            deleteFileVersionsInFoldersAndSubFolders(subFolder, true);
                        }

                    }

                }

            }
            catch (Exception ex)
            {

            }


            finally
            {

            }

        }


        /// <summary> 
        /// Recycles files located in this folder plus any other sub folders underneath it using an iterative method 
        /// </summary> 
        /// <param name="instance">A SharePoint folder instance</param> 
        /// <param name="includeChildFolders">A boolean specifying whether to include child folders or not</param> 
        private static void recycleFileVersionsInFoldersAndSubFolders(SPFolder instance, bool includeChildren)
        {


            try
            {

                SPFileCollection files = instance.Files;
                if (files != null && files.Count > 0)
                {
                    foreach (SPFile file in files)
                    {
                        if (file.Versions.Count > 0)
                        {
                            versionsRecycled += file.Versions.Count;
                            filesRecycled += 1;
                            System.Console.WriteLine("Recycling versions of file: {0}", file.Url);
                            file.Versions.RecycleAll();
                        }

                    }

                }


                if (includeChildren)
                {


                    if (instance.SubFolders != null)
                    {


                        foreach (SPFolder subFolder in instance.SubFolders)
                        {


                            // Recycle second level sub folder files 
                            recycleFileVersionsInFoldersAndSubFolders(subFolder,true);
                        }

                    }

                }

            }


            catch (Exception ex)
            {

            }


            finally
            {

            }

        }


        /// <summary> 

        /// This method insure that we have a valid site colleciton with the specified path in the current server farm 

        /// </summary> 

        /// <param name="siteCollectionUrl">A path to the specified site collection</param> 

        /// <returns>A boolean value to indicate if the site collection was found or not</returns> 

        private static bool isValidSiteCollection(string siteCollectionUrl)
        {


            // Get a reference to the local server farm running 
            SPFarm mossFarm = SPFarm.Local;


            // Get a reference to the service hosting all web applications in this farm 
            SPWebService service = mossFarm.Services.GetValue<SPWebService>("");

            bool foundSiteCollection = false;

            // Look for the site collection with the specified path 
            foreach (SPWebApplication webApplication in service.WebApplications)
            {
                SPSiteCollection siteCollections = webApplication.Sites;

                foreach (SPSite siteCollection in siteCollections)
                {
                    if (siteCollection.Url == siteCollectionUrl.ToLower())
                    {
                        foundSiteCollection = true;
                        break;
                    }
                }


                if (foundSiteCollection)
                {
                    break;
                }
            }

            return foundSiteCollection;
        }

    }

}

